package com.wg.net.server.tcp;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.core.utils.ByteBufUtils;
import com.wg.net.NetProtocol;
import com.wg.net.server.tcp.init.InitializeHandler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * 协议初始化解码器（用于识别TCP/WebSocket协议）
 * <p>
 * 功能：在握手阶段读取字节流前缀，判断客户端使用的协议类型（TCP/WebSocket），
 * 并将请求转发至对应的初始化处理器（SocketInitializeHandler/WebsocketInitializeHandler）。
 *
 * @author 少爷123
 */
public class InitializeDecoder extends ByteToMessageDecoder {
    private static final Log log = LogFactory.get();

    /**
     * WebSocket 握手请求的前缀（"GET /" 是WebSocket升级请求的标准起始行）
     */
    private static final String WEBSOCKET_HANDSHAKE_PREFIX = "GET /";
    /**
     * WebSocket 前缀长度（用于快速判断）
     */
    private static final int WEBSOCKET_PREFIX_LENGTH = WEBSOCKET_HANDSHAKE_PREFIX.length();

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in.readableBytes() < WEBSOCKET_PREFIX_LENGTH) {
            log.debug("可读字节不足（当前: {}，需要: {}），暂无法判断协议类型，等待更多数据...",
                    in.readableBytes(), WEBSOCKET_PREFIX_LENGTH);
            return; // 不足时等待后续数据
        }

        // 标记当前读位置，以便后续重置
        in.markReaderIndex();

        // 读取前WEBSOCKET_PREFIX_LENGTH字节，判断是否为WebSocket握手请求
        String prefix = ByteBufUtils.readString(in, WEBSOCKET_PREFIX_LENGTH);
        NetProtocol protocol = prefix.startsWith(WEBSOCKET_HANDSHAKE_PREFIX)
                ? NetProtocol.WEBSOCKET
                : NetProtocol.TCP;

        // 重置读位置，避免影响后续解码
        in.resetReaderIndex();

        log.debug("检测到协议类型: {}", protocol);

        // 获取对应协议的初始化处理器并处理
        InitializeHandler handler = InitializeHandlerManager.getInstance().getHandler(protocol);
        if (handler == null) {
            log.error("未找到协议类型对应的初始化处理器: {}", protocol);
            ctx.close(); // 无处理器处理，关闭连接
            return;
        }

        handler.handle(ctx);

        // 移除当前解码器（已完成协议判断，后续由目标处理器处理）
        ctx.pipeline().remove(this);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("协议初始化解码器发生异常", cause);
        ctx.close(); // 异常时关闭连接
    }
}